package com.test.security.springsecuritydemo11.service;

import com.test.security.springsecuritydemo11.dao.OtpRepository;
import com.test.security.springsecuritydemo11.dao.UserRepository;
import com.test.security.springsecuritydemo11.entity.Otp;
import com.test.security.springsecuritydemo11.entity.User;
import com.test.security.springsecuritydemo11.util.GenerateCodeUtil;
import java.util.Optional;
import javax.transaction.Transactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * Created with IntelliJ IDEA.
 * Description:
 *
 * @author lzy
 * @since 2023/1/4 上午11:54
 */
@Transactional
@Service
public class UserServiceImpl implements UserService {
    private PasswordEncoder passwordEncoder;
    private UserRepository userRepository;
    private OtpRepository otpRepository;

    @Autowired
    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setOtpRepository(OtpRepository otpRepository) {
        this.otpRepository = otpRepository;
    }

    @Override
    public void addUser(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        userRepository.save(user);
    }

    /**
     * @param user
     */
    @Override
    public void authUser(User user) {
        final Optional<User> optionalUser = userRepository.findUserByUsername(user.getUsername());
        optionalUser.map(u -> {
            if (passwordEncoder.matches(user.getPassword(), u.getPassword())) {
                renewOtp(u);
                return true;
            } else {
                throw new BadCredentialsException("Bad credentials");
            }
        }).orElseThrow(() -> new BadCredentialsException("Bad credentials"));
    }

    /**
     * @param otpToValidate
     * @return
     */
    @Override
    public boolean check(Otp otpToValidate) {
        final Optional<Otp> userOtp = otpRepository.findOtpByUsername(otpToValidate.getUsername());
        return userOtp
                .map(otp -> StringUtils.equals(otpToValidate.getCode(), otp.getCode()))
                .orElse(false);
    }

    private void renewOtp(User u) {
        final String code = GenerateCodeUtil.generateCode();
        final Optional<Otp> userOtp = otpRepository.findOtpByUsername(u.getUsername());
        userOtp.ifPresentOrElse(otp -> otp.setCode(code), () -> {
            Otp otp = new Otp();
            otp.setUsername(u.getUsername());
            otp.setCode(code);
            otpRepository.save(otp);
        });
    }
}
